<?php
namespace app\controller;
use think\facade\Log; // 添加到文件顶部的use部分
use app\BaseController;
use app\model\OperationLog;
use app\model\User;
use app\model\Device;
use app\model\DeviceData;
use think\facade\Db;
use think\facade\Filesystem;


class Monitor extends BaseController
{
    /**
     * 获取系统基本信息
     */
    public function server()
    {
        $serverInfo = [
            'os' => PHP_OS,
            'php_version' => PHP_VERSION,
            'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? '',
            'server_name' => $_SERVER['SERVER_NAME'] ?? '',
            'server_protocol' => $_SERVER['SERVER_PROTOCOL'] ?? '',
            'server_port' => $_SERVER['SERVER_PORT'] ?? '',
            'remote_addr' => $_SERVER['REMOTE_ADDR'] ?? '',
            'time' => date('Y-m-d H:i:s'),
            'timezone' => date_default_timezone_get(),
            'db_type' => 'MySQL',
            'db_version' => $this->getDatabaseVersion()
        ];
        
        // 获取磁盘使用情况
        $disk_total = disk_total_space('/');
        $disk_free = disk_free_space('/');
        $disk_used = $disk_total - $disk_free;
        $serverInfo['disk_total'] = $this->formatBytes($disk_total);
        $serverInfo['disk_free'] = $this->formatBytes($disk_free);
        $serverInfo['disk_used'] = $this->formatBytes($disk_used);
        $serverInfo['disk_usage'] = round($disk_used / $disk_total * 100, 2);
        
        // 获取内存使用情况（跨平台）
        $memInfo = [];
        if (stripos(PHP_OS, 'Linux') !== false) {
            $memInfo = $this->getLinuxMemoryInfo();
        } elseif (stripos(PHP_OS, 'WIN') !== false) {
            $memInfo = $this->getWindowsMemoryInfo();
        }
        $serverInfo = array_merge($serverInfo, $memInfo);
        
        // 获取CPU使用情况（跨平台）
        $cpuInfo = [];
        if (stripos(PHP_OS, 'Linux') !== false) {
            $cpuInfo = $this->getLinuxCpuInfo();
        } elseif (stripos(PHP_OS, 'WIN') !== false) {
            $cpuInfo = $this->getWindowsCpuInfo();
        }
        $serverInfo = array_merge($serverInfo, $cpuInfo);
        
        return $this->success('获取成功', $serverInfo);
    }
    
    /**
     * 获取系统运行统计信息
     */
    public function statistics()
    {
        // 用户统计
        $userTotal = User::count();
        $userToday = User::whereDay('create_time', date('Y-m-d'))->count();
        $userActive = User::where('status', 1)->count();
        
        // 设备统计
        $deviceTotal = Device::count();
        $deviceOnline = Device::where('status', 1)->count();
        $deviceOffline = $deviceTotal - $deviceOnline;
        
        // 数据统计
        $dataTotal = DeviceData::count();
        $dataToday = DeviceData::whereDay('create_time', date('Y-m-d'))->count();
        
        // 操作日志统计
        $logTotal = OperationLog::count();
        $logToday = OperationLog::whereDay('operate_time', date('Y-m-d'))->count();
        $logSuccess = OperationLog::where('status', 1)->count();
        $logFail = OperationLog::where('status', 0)->count();
        
        return $this->success('获取成功', [
            'user' => [
                'total' => $userTotal,
                'today' => $userToday,
                'active' => $userActive,
                'inactive' => $userTotal - $userActive
            ],
            'device' => [
                'total' => $deviceTotal,
                'online' => $deviceOnline,
                'offline' => $deviceOffline,
                'online_rate' => $deviceTotal > 0 ? round($deviceOnline / $deviceTotal * 100, 2) : 0
            ],
            'data' => [
                'total' => $dataTotal,
                'today' => $dataToday
            ],
            'log' => [
                'total' => $logTotal,
                'today' => $logToday,
                'success' => $logSuccess,
                'fail' => $logFail,
                'success_rate' => $logTotal > 0 ? round($logSuccess / $logTotal * 100, 2) : 0
            ]
        ]);
    }
    
    /**
     * 获取在线用户列表
     */
    public function online()
    {
        // 获取请求参数
        $params = $this->request->get();
        
        // 假设在线用户是最近30分钟内有登录记录的用户
        $query = User::whereTime('last_login_time', '>=', date('Y-m-d H:i:s', time() - 30 * 60))
            ->withoutField('password')
            ->order('last_login_time', 'desc');
        
        // 按用户名搜索
        if (!empty($params['username'])) {
            $query = $query->whereLike('username', '%' . $params['username'] . '%');
        }
        
        // 分页
        $list = $query->paginate([
            'list_rows' => $params['pageSize'] ?? 10,
            'page' => $params['page'] ?? 1,
        ]);
        
        return $this->success('获取成功', $list);
    }
    
    /**
     * 获取数据库大小信息
     */
    public function database()
    {
        // 获取数据库名
        $database = config('database.connections.mysql.database');
        
        // 获取数据库表信息
        $tables = Db::query("SHOW TABLE STATUS FROM `{$database}`");
        
        $totalSize = 0;
        $tableList = [];
        
        foreach ($tables as $table) {
            $size = $table['Data_length'] + $table['Index_length'];
            $totalSize += $size;
            
            $tableList[] = [
                'name' => $table['Name'],
                'engine' => $table['Engine'],
                'rows' => $table['Rows'],
                'data_size' => $this->formatBytes($table['Data_length']),
                'index_size' => $this->formatBytes($table['Index_length']),
                'total_size' => $this->formatBytes($size),
                'collation' => $table['Collation'],
                'create_time' => $table['Create_time'],
                'update_time' => $table['Update_time']
            ];
        }
        
        return $this->success('获取成功', [
            'database' => $database,
            'total_size' => $this->formatBytes($totalSize),
            'table_count' => count($tables),
            'tables' => $tableList
        ]);
    }
    
    /**
     * 获取缓存信息
     */
    public function cache()
    {
        // 获取缓存目录
        $runtimePath = app()->getRuntimePath();
        
        // 获取缓存目录大小
        $cacheSize = $this->getDirSize($runtimePath . 'cache');
        
        // 获取日志目录大小
        $logSize = $this->getDirSize($runtimePath . 'log');
        
        // 获取临时目录大小
        $tempSize = $this->getDirSize($runtimePath . 'temp');
        
        // 获取上传目录大小
        $uploadSize = $this->getDirSize(public_path() . 'uploads');
        
        return $this->success('获取成功', [
            'cache' => [
                'path' => $runtimePath . 'cache',
                'size' => $this->formatBytes($cacheSize)
            ],
            'log' => [
                'path' => $runtimePath . 'log',
                'size' => $this->formatBytes($logSize)
            ],
            'temp' => [
                'path' => $runtimePath . 'temp',
                'size' => $this->formatBytes($tempSize)
            ],
            'upload' => [
                'path' => public_path() . 'uploads',
                'size' => $this->formatBytes($uploadSize)
            ],
            'total' => $this->formatBytes($cacheSize + $logSize + $tempSize + $uploadSize)
        ]);
    }
    
    /**
     * 清空缓存
     * @param string $type 缓存类型
     */
    public function clearCache($type = 'all')
    {
        // 获取运行时目录
        $runtimePath = app()->getRuntimePath();
        
        switch ($type) {
            case 'cache':
                $this->delDir($runtimePath . 'cache');
                break;
            case 'log':
                $this->delDir($runtimePath . 'log');
                break;
            case 'temp':
                $this->delDir($runtimePath . 'temp');
                break;
            case 'all':
                $this->delDir($runtimePath . 'cache');
                $this->delDir($runtimePath . 'log');
                $this->delDir($runtimePath . 'temp');
                break;
            default:
                return $this->error('缓存类型不存在');
        }
        
        return $this->success('清空缓存成功');
    }
    
    /**
     * 获取数据库版本
     * @return string 数据库版本
     */
    private function getDatabaseVersion()
    {
        $version = Db::query('SELECT VERSION() as version');
        return $version[0]['version'] ?? '';
    }
    
    /**
     * 格式化字节大小
     * @param int $bytes 字节数
     * @param int $precision 精度
     * @return string 格式化后的大小
     */
    private function formatBytes($bytes, $precision = 2)
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
        
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        
        $bytes /= (1 << (10 * $pow));
        
        return round($bytes, $precision) . ' ' . $units[$pow];
    }
    
    /**
     * 获取目录大小
     * @param string $dir 目录路径
     * @return int 目录大小（字节）
     */
    private function getDirSize($dir)
    {
        if (!is_dir($dir)) {
            return 0;
        }
        
        $size = 0;
        $handle = opendir($dir);
        
        if ($handle) {
            while (($file = readdir($handle)) !== false) {
                if ($file != '.' && $file != '..') {
                    $path = $dir . '/' . $file;
                    if (is_dir($path)) {
                        $size += $this->getDirSize($path);
                    } else {
                        $size += filesize($path);
                    }
                }
            }
            closedir($handle);
        }
        
        return $size;
    }
    
    /**
     * 删除目录及其内容
     * @param string $dir 目录路径
     * @return bool 是否成功
     */
    private function delDir($dir)
    {
        if (!is_dir($dir)) {
            return true;
        }
        
        $handle = opendir($dir);
        
        if ($handle) {
            while (($file = readdir($handle)) !== false) {
                if ($file != '.' && $file != '..') {
                    $path = $dir . '/' . $file;
                    if (is_dir($path)) {
                        $this->delDir($path);
                    } else {
                        @unlink($path);
                    }
                }
            }
            closedir($handle);
            
            // 删除目录本身，但保留目录
            $files = scandir($dir);
            if (count($files) <= 2) { // 只有 . 和 .. 两个目录
                return true;
            }
            return true;
        }
        
        return false;
    }
    
    /**
     * 获取Linux系统内存信息
     * @return array 内存信息
     */
    private function getLinuxMemoryInfo()
    {
        $memInfo = [];
        
        try {
            $cmd = "free -b | grep 'Mem'";
            exec($cmd, $output);
            
            if (!empty($output)) {
                $values = preg_split('/\s+/', $output[0]);
                
                $total = isset($values[1]) ? intval($values[1]) : 0;
                $used = isset($values[2]) ? intval($values[2]) : 0;
                $free = isset($values[3]) ? intval($values[3]) : 0;
                $shared = isset($values[4]) ? intval($values[4]) : 0;
                $buffers = isset($values[5]) ? intval($values[5]) : 0;
                $cached = isset($values[6]) ? intval($values[6]) : 0;
                
                $memInfo['memory_total'] = $this->formatBytes($total);
                $memInfo['memory_used'] = $this->formatBytes($used);
                $memInfo['memory_free'] = $this->formatBytes($free);
                $memInfo['memory_shared'] = $this->formatBytes($shared);
                $memInfo['memory_buffers'] = $this->formatBytes($buffers);
                $memInfo['memory_cached'] = $this->formatBytes($cached);
                $memInfo['memory_usage'] = round($used / $total * 100, 2);
            }
        } catch (\Exception $e) {
            // 错误处理改为记录日志并返回空数组
            Log::error('获取内存信息失败：' . $e->getMessage());
            return [];
        }
        
        return $memInfo;
    }
    
    /**
     * 获取Linux系统CPU信息
     * @return array CPU信息
     */
    private function getLinuxCpuInfo()
    {
        $cpuInfo = [];
        
        try {
            // 获取CPU型号
            $cmd = "cat /proc/cpuinfo | grep 'model name' | head -n 1";
            exec($cmd, $output);
            
            if (!empty($output)) {
                $model = explode(":", $output[0]);
                $cpuInfo['cpu_model'] = isset($model[1]) ? trim($model[1]) : '';
            }
            
            // 获取CPU核心数
            $cmd = "cat /proc/cpuinfo | grep 'processor' | wc -l";
            exec($cmd, $output);
            
            if (!empty($output)) {
                $cpuInfo['cpu_cores'] = intval($output[0]);
            }
            
            // 获取CPU使用率
            $cmd = "top -bn1 | grep 'Cpu(s)' | awk '{print $2 + $4}'";
            exec($cmd, $output);
            
            if (!empty($output)) {
                $cpuInfo['cpu_usage'] = round(floatval($output[0]), 2);
            }
        } catch (\Exception $e) {
            Log::error('获取CPU信息失败：' . $e->getMessage());
            return [];
        }
        
        return $cpuInfo;
    }
    
    /**
     * 获取Windows系统内存信息
     */
    private function getWindowsMemoryInfo()
    {
        $memInfo = [];
        try {
            // 获取物理内存信息（单位：字节）
            $output = [];
            exec('wmic OS get TotalVisibleMemorySize,FreePhysicalMemory /Value', $output);
            
            $total = 0;
            $free = 0;
            foreach ($output as $line) {
                if (preg_match('/TotalVisibleMemorySize=(\d+)/', $line, $matches)) {
                    $total = intval($matches[1]) * 1024; // 转换为字节
                }
                if (preg_match('/FreePhysicalMemory=(\d+)/', $line, $matches)) {
                    $free = intval($matches[1]) * 1024; // 转换为字节
                }
            }
            
            if ($total > 0) {
                $used = $total - $free;
                $memInfo['memory_total'] = $this->formatBytes($total);
                $memInfo['memory_used'] = $this->formatBytes($used);
                $memInfo['memory_free'] = $this->formatBytes($free);
                $memInfo['memory_usage'] = round($used / $total * 100, 2);
            }
        } catch (\Exception $e) {
            Log::error('获取内存信息失败：' . $e->getMessage());
            return [];
        }
        return $memInfo;
    }
    
    /**
     * 获取Windows系统CPU信息
     */
    private function getWindowsCpuInfo()
    {
        $cpuInfo = [];
        try {
            // 改进后的CPU信息获取逻辑
            exec('wmic cpu get Name,NumberOfCores,NumberOfLogicalProcessors /Value', $output);
            
            $model = '';
            $cores = 0;
            $logicalProcessors = 0;
            foreach ($output as $line) {
                if (preg_match('/Name=(.+)/', $line, $matches)) {
                    $model = trim($matches[1]);
                }
                if (preg_match('/NumberOfCores=(\d+)/', $line, $matches)) {
                    $cores = intval($matches[1]);
                }
                if (preg_match('/NumberOfLogicalProcessors=(\d+)/', $line, $matches)) {
                    $logicalProcessors = intval($matches[1]);
                }
            }

            // 合并核心数信息
            $cpuInfo['cpu_model'] = $model;
            $cpuInfo['cpu_cores'] = $cores;
            $cpuInfo['cpu_threads'] = $logicalProcessors; // 新增逻辑处理器数量

            // 备用方案：通过WMI获取
            if ($usage === 0) {
                exec('wmic cpu get loadpercentage /Value', $wmiOutput);
                foreach ($wmiOutput as $line) {
                    if (preg_match('/LoadPercentage=(\d+)/', $line, $matches)) {
                        $usage = intval($matches[1]);
                        break;
                    }
                }
            }

            $cpuInfo['cpu_usage'] = $usage;
        } catch (\Exception $e) {
            Log::error('CPU信息获取失败: ' . $e->getMessage());
            $cpuInfo['cpu_usage'] = 0;
        }
        return $cpuInfo;
    }
} 